package be.donovan.gui.helper;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback;
import org.springframework.util.ReflectionUtils.MethodFilter;

import be.donovan.gui.helper.components.MVCPanel;
import be.donovan.gui.helper.components.ViewI;

public class GuiHelper {
	static {
		for (Object object : UIManager.getLookAndFeelDefaults().keySet()) {
			if (object.toString().endsWith(".disabledForeground") || object.toString().endsWith(".inactiveForeground")
					|| object.toString().endsWith(".disabledText")) {
				UIManager.put(object.toString(), Color.BLACK);
			}
		}
		UIManager.put("ComboBox.background", Color.WHITE);
	}

	public static void showView(MVCPanel aView) {
		MainFrame gui = MainFrame.getInstance();
		gui.add(aView);
		gui.invalidate();
	}

	public static void showView(ViewI view) {
		if (view instanceof MVCPanel) {
			showView((MVCPanel) view);
		} else {
			System.out.println("GuiHelper.showView() : UNKNOWN CLASS");
		}

	}

	public static void hideButtons(Container parent) {
		for (final Component child : parent.getComponents()) {
			if (child instanceof Container) {
				hideButtons((Container) child);
			}
			if (child instanceof JButton) {
				child.setVisible(false);
			}
		}
	}

	public static void showButtons(Container parent) {
		for (final Component child : parent.getComponents()) {
			if (child instanceof Container) {
				showButtons((Container) child);
			}
			if (child instanceof JButton) {
				child.setVisible(true);
			}
		}
	}

	public static void disableComponents(Component... c) {
		for (final Component component : c) {
			component.setEnabled(false);
			ReflectionUtils.doWithMethods(component.getClass(), new MethodCallback() {
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
					try {
						method.invoke(component, false);
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
				}
			}, editableMethodFilter);
		}
	}

	public static void enableComponents(Component... c) {
		for (final Component component : c) {
			component.setEnabled(true);
			ReflectionUtils.doWithMethods(component.getClass(), new MethodCallback() {
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
					try {
						method.invoke(component, true);
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
				}
			}, editableMethodFilter);
		}
	}

	public static void disableChildren(Container parent) {
		for (final Component child : parent.getComponents()) {
			if (child instanceof Container) {
				if (mustBeDisabled(child)) {
					disableComponents(child);
				}
				disableChildren((Container) child);
			}
		}
	}

	public static void enableChildren(Container parent) {
		for (final Component child : parent.getComponents()) {
			if (child instanceof Container) {
				if (mustBeDisabled(child)) {
					enableComponents(child);
				}
				enableChildren((Container) child);
			}
		}
	}

	private static Class[] exceptions = new Class[] { JTabbedPane.class, JPanel.class, JLabel.class };

	private static boolean mustBeDisabled(final Component child) {
		for (Class clazz : exceptions) {
			if (clazz.isInstance(child) || child.getClass().getName().contains(clazz.getSimpleName())) {
				return false;
			}
		}
		return true;
	}

	public static void hideComponents(Component... c) {
		for (final Component component : c) {
			component.setVisible(false);
		}
	}

	public static void showComponents(Component... c) {
		for (final Component component : c) {
			component.setVisible(true);
		}
	}

	private static MethodFilter editableMethodFilter = new MethodFilter() {
		public boolean matches(Method method) {
			return (method.getName().equals("setEditable"));
		}
	};

}
